﻿using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;


namespace IMIForUnity
{

    /// <summary>
    /// Dispatches events to main thread
    /// </summary>
    public class MainThreadDispatcher
    {
        private const int QUEUE_LEN_MAX = 100;
        private static MainThreadDispatcher instance;
        private static object _lock = new object();

        private ImiManager imiManager;

        /// <summary>
        /// Action Queue for executing in main thread
        /// </summary>
        private readonly static Queue<Action> _executionQueue = new Queue<Action>();


        public static MainThreadDispatcher GetInstance()
        {
            if (instance == null)
            {
                lock (_lock)
                {
                    if (instance == null)
                    {
                        instance = new MainThreadDispatcher();
                    }
                }
            }
            return instance;
        }
        private MainThreadDispatcher()
        {
            imiManager = ImiManager.GetInstance();
        }


        public void update()
        {
            lock (_executionQueue)
            {
                while (_executionQueue.Count > 0)
                {
                    _executionQueue.Dequeue().Invoke();
                }
            }

        }

        /// <summary>
        /// Locks the queue and adds the IEnumerator to the queue
        /// </summary>
        /// <param name="action">IEnumerator function that will be executed from the main thread.</param>
        public void Enqueue(IEnumerator action)
        {
            lock (_executionQueue)
            {
                if(_executionQueue.Count > QUEUE_LEN_MAX)
                {
                    //Too Much actions to be executed
                    //To avoid blocking the main thread, aborting without invoke
                    _executionQueue.Dequeue();
                }
                _executionQueue.Enqueue(() =>
                {
                    imiManager.StartCoroutine(action);
                });
            }
        }

        /// <summary>
        /// Locks the queue and adds the Action to the queue
        /// </summary>
        /// <param name="action">function that will be executed from the main thread.</param>
        public void Enqueue(Action action)
        {
            Enqueue(ActionWrapper(action));
        }


        IEnumerator ActionWrapper(Action a)
        {
            a();
            yield return null;
        }


    }

}